----------------------------------------------------------------------------------
-- Company:        Johns Hopkins University 
-- Engineer:       Kevin Green
-- 
-- Create Date:    22:38:52 11/29/2011 
-- Design Name:    game_logic_top
-- Module Name:    game_logic_top - RTL 
-- Project Name:   top_gillis_green
-- Target Devices: 
-- Tool versions: 
-- Description:    This is the game logic top module.  
--
-- Dependencies:   valid_move_gen
--						 mask_gen
--                 associated picoblaze modules
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE; 
use IEEE.STD_LOGIC_1164.ALL;
use work.game_logic_pkg.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
-- library UNISIM;
-- use UNISIM.VComponents.all;

entity game_logic_top is
    Port ( clk50 : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           play : in  STD_LOGIC;
           row : in  STD_LOGIC_VECTOR (2 downto 0);
           col : in  STD_LOGIC_VECTOR (2 downto 0);
			  
			  -- interconnect signals to vga block
			  player : out std_logic;
			  game_board : out g_board;
			  done : out std_logic;
			  valid_move : out std_logic);
end game_logic_top;

architecture RTL of game_logic_top is

-- white and black bitboards
-- persistent save of positions
signal white_board : board;
signal black_board : board;

-- internal signals
signal t_row : std_logic_vector(2 downto 0);
signal t_col : std_logic_vector(2 downto 0);
signal t_done : std_logic;
signal t_player : std_logic;

signal sel : std_logic_vector(1 downto 0);
signal num : std_logic_vector(2 downto 0);

-- picoblaze signals
signal address       : std_logic_vector( 9 downto 0);
signal instruction   : std_logic_vector(17 downto 0);
signal port_id       : std_logic_vector( 7 downto 0);
signal write_strobe  : std_logic;
signal out_port      : std_logic_vector( 7 downto 0);
signal read_strobe   : std_logic;
signal in_port       : std_logic_vector( 7 downto 0);

-- mask signal
signal mask_data_out : std_logic_vector( 7 downto 0);

-- valid move signal
signal move_data_out : std_logic_vector( 7 downto 0);
signal move : std_logic_vector(7 downto 0);

-- play sync signals
signal sync_play : std_logic;
signal t_play : std_logic;

begin

-- syncronizers for play signal
-- two stage
process(clk50, reset) is
begin
	if(reset = '1') then
		sync_play <= '0';
		t_play <= '0';
	elsif(rising_edge(clk50)) then
		sync_play <= play;
		t_play <= sync_play;
	end if;
end process;

--mapping for current board status to game_board output
rank_array : for I in 0 to 7 generate
begin
	file_array : for J in 0 to 7 generate
	begin
		game_board(I,J) <= BLACK when black_board(I)(J) = '1' else
								 WHITE when white_board(I)(J) = '1' else
								 EMPTY;
	end generate file_array;
end generate rank_array;

-- This block is the write demux and t_col and t_row
-- register assignments.  The write demux is controlled
-- by the port_id signal and enabled with the write_strobe
-- signal.
process(clk50, reset) is
	variable u_temp : unsigned(2 downto 0);
begin
	if(reset = '1') then
		white_board <= (others => (others => '0'));
		white_board(4)(4) <= '1';
		white_board(3)(3) <= '1';
		black_board <= (others => (others => '0'));
		black_board(3)(4) <= '1';
		black_board(4)(3) <= '1';
		t_col <= "000";
		t_row <= "000";
		t_player <= '0';
		t_done <= '0';
		valid_move <= '1';
		sel <= "00";
		num <= "000";
	elsif(rising_edge(clk50)) then
		if(t_play = '1') then
			t_col <= col;
			t_row <= row;
		end if;
		
		if(write_strobe = '1') then
			case(port_id) is
				when x"09" =>
					num <= out_port(2 downto 0);
				when x"16" =>
					sel <= out_port(1 downto 0);
				when x"15" =>
					t_done <= out_port(0);
				when x"00" =>
					t_player <= out_port(0);
				when x"0a" => 
					t_row <= out_port(2 downto 0);
				when x"0b" =>
					if(t_player = '0') then
						black_board(to_integer(unsigned(t_row))) <= out_port;
					else 
						white_board(to_integer(unsigned(t_row))) <= out_port;
					end if;
				when x"0c" =>
					if(t_player = '0') then
						white_board(to_integer(unsigned(t_row))) <= out_port;
					else 
						black_board(to_integer(unsigned(t_row))) <= out_port;
					end if;
				when x"0f" =>
					if(t_player = '0') then
						black_board(7)(to_integer(unsigned(t_col))) <= out_port(7);
						black_board(6)(to_integer(unsigned(t_col))) <= out_port(6);
						black_board(5)(to_integer(unsigned(t_col))) <= out_port(5);
						black_board(4)(to_integer(unsigned(t_col))) <= out_port(4);
						black_board(3)(to_integer(unsigned(t_col))) <= out_port(3);
						black_board(2)(to_integer(unsigned(t_col))) <= out_port(2);
						black_board(1)(to_integer(unsigned(t_col))) <= out_port(1);
						black_board(0)(to_integer(unsigned(t_col))) <= out_port(0);
					else
						white_board(7)(to_integer(unsigned(t_col))) <= out_port(7);
						white_board(6)(to_integer(unsigned(t_col))) <= out_port(6);
						white_board(5)(to_integer(unsigned(t_col))) <= out_port(5);
						white_board(4)(to_integer(unsigned(t_col))) <= out_port(4);
						white_board(3)(to_integer(unsigned(t_col))) <= out_port(3);
						white_board(2)(to_integer(unsigned(t_col))) <= out_port(2);
						white_board(1)(to_integer(unsigned(t_col))) <= out_port(1);
						white_board(0)(to_integer(unsigned(t_col))) <= out_port(0);
					end if;
				when x"12" =>
					if(t_player = '0') then
						white_board(7)(to_integer(unsigned(t_col))) <= out_port(7);
						white_board(6)(to_integer(unsigned(t_col))) <= out_port(6);
						white_board(5)(to_integer(unsigned(t_col))) <= out_port(5);
						white_board(4)(to_integer(unsigned(t_col))) <= out_port(4);
						white_board(3)(to_integer(unsigned(t_col))) <= out_port(3);
						white_board(2)(to_integer(unsigned(t_col))) <= out_port(2);
						white_board(1)(to_integer(unsigned(t_col))) <= out_port(1);
						white_board(0)(to_integer(unsigned(t_col))) <= out_port(0);
					else
						black_board(7)(to_integer(unsigned(t_col))) <= out_port(7);
						black_board(6)(to_integer(unsigned(t_col))) <= out_port(6);
						black_board(5)(to_integer(unsigned(t_col))) <= out_port(5);
						black_board(4)(to_integer(unsigned(t_col))) <= out_port(4);
						black_board(3)(to_integer(unsigned(t_col))) <= out_port(3);
						black_board(2)(to_integer(unsigned(t_col))) <= out_port(2);
						black_board(1)(to_integer(unsigned(t_col))) <= out_port(1);
						black_board(0)(to_integer(unsigned(t_col))) <= out_port(0);					
					end if;
				when x"10" =>
					if(t_player = '0') then
						u_temp := (unsigned(t_row)-(7-unsigned(t_col)));
						black_board(to_integer(u_temp))(7)   <= out_port(7);
						black_board(to_integer(u_temp+1))(6) <= out_port(6);
						black_board(to_integer(u_temp+2))(5) <= out_port(5);
						black_board(to_integer(u_temp+3))(4) <= out_port(4);
						black_board(to_integer(u_temp+4))(3) <= out_port(3);
						black_board(to_integer(u_temp+5))(2) <= out_port(2);
						black_board(to_integer(u_temp+6))(1) <= out_port(1);
						black_board(to_integer(u_temp+7))(0) <= out_port(0);
					else 
						u_temp := (unsigned(t_row)-(7-unsigned(t_col)));
						white_board(to_integer(u_temp))(7)   <= out_port(7);
						white_board(to_integer(u_temp+1))(6) <= out_port(6);
						white_board(to_integer(u_temp+2))(5) <= out_port(5);
						white_board(to_integer(u_temp+3))(4) <= out_port(4);
						white_board(to_integer(u_temp+4))(3) <= out_port(3);
						white_board(to_integer(u_temp+5))(2) <= out_port(2);
						white_board(to_integer(u_temp+6))(1) <= out_port(1);
						white_board(to_integer(u_temp+7))(0) <= out_port(0);
					end if;
				when x"13" =>
					if(t_player = '0') then
						u_temp := (unsigned(t_row)-(7-unsigned(t_col)));
						white_board(to_integer(u_temp))(7)   <= out_port(7);
						white_board(to_integer(u_temp+1))(6) <= out_port(6);
						white_board(to_integer(u_temp+2))(5) <= out_port(5);
						white_board(to_integer(u_temp+3))(4) <= out_port(4);
						white_board(to_integer(u_temp+4))(3) <= out_port(3);
						white_board(to_integer(u_temp+5))(2) <= out_port(2);
						white_board(to_integer(u_temp+6))(1) <= out_port(1);
						white_board(to_integer(u_temp+7))(0) <= out_port(0);					
					else
						u_temp := (unsigned(t_row)-(7-unsigned(t_col)));
						black_board(to_integer(u_temp))(7)   <= out_port(7);
						black_board(to_integer(u_temp+1))(6) <= out_port(6);
						black_board(to_integer(u_temp+2))(5) <= out_port(5);
						black_board(to_integer(u_temp+3))(4) <= out_port(4);
						black_board(to_integer(u_temp+4))(3) <= out_port(3);
						black_board(to_integer(u_temp+5))(2) <= out_port(2);
						black_board(to_integer(u_temp+6))(1) <= out_port(1);
						black_board(to_integer(u_temp+7))(0) <= out_port(0);					
					end if;
					
				when x"11" =>
					if(t_player = '0') then 
						u_temp := ((7-unsigned(t_col))+unsigned(t_row));
						black_board(to_integer(u_temp))(7)   <= out_port(7);
						black_board(to_integer(u_temp-1))(6) <= out_port(6);
						black_board(to_integer(u_temp-2))(5) <= out_port(5);
						black_board(to_integer(u_temp-3))(4) <= out_port(4);
						black_board(to_integer(u_temp-4))(3) <= out_port(3);
						black_board(to_integer(u_temp-5))(2) <= out_port(2);
						black_board(to_integer(u_temp-6))(1) <= out_port(1);
						black_board(to_integer(u_temp-7))(0) <= out_port(0);		
					else
						u_temp := ((7-unsigned(t_col))+unsigned(t_row));
						white_board(to_integer(u_temp))(7)   <= out_port(7);
						white_board(to_integer(u_temp-1))(6) <= out_port(6);
						white_board(to_integer(u_temp-2))(5) <= out_port(5);
						white_board(to_integer(u_temp-3))(4) <= out_port(4);
						white_board(to_integer(u_temp-4))(3) <= out_port(3);
						white_board(to_integer(u_temp-5))(2) <= out_port(2);
						white_board(to_integer(u_temp-6))(1) <= out_port(1);
						white_board(to_integer(u_temp-7))(0) <= out_port(0);						
					end if;
					
				when x"14" =>
					if(t_player = '0') then
						u_temp := ((7-unsigned(t_col))+unsigned(t_row));
						white_board(to_integer(u_temp))(7)   <= out_port(7);
						white_board(to_integer(u_temp-1))(6) <= out_port(6);
						white_board(to_integer(u_temp-2))(5) <= out_port(5);
						white_board(to_integer(u_temp-3))(4) <= out_port(4);
						white_board(to_integer(u_temp-4))(3) <= out_port(3);
						white_board(to_integer(u_temp-5))(2) <= out_port(2);
						white_board(to_integer(u_temp-6))(1) <= out_port(1);
						white_board(to_integer(u_temp-7))(0) <= out_port(0);
					else
						u_temp := ((7-unsigned(t_col))+unsigned(t_row));
						black_board(to_integer(u_temp))(7)   <= out_port(7);
						black_board(to_integer(u_temp-1))(6) <= out_port(6);
						black_board(to_integer(u_temp-2))(5) <= out_port(5);
						black_board(to_integer(u_temp-3))(4) <= out_port(4);
						black_board(to_integer(u_temp-4))(3) <= out_port(3);
						black_board(to_integer(u_temp-5))(2) <= out_port(2);
						black_board(to_integer(u_temp-6))(1) <= out_port(1);
						black_board(to_integer(u_temp-7))(0) <= out_port(0);
					end if;
				when x"0d" => 
					valid_move <= out_port(0);
				when others =>
			end case;
			
		end if;
		
	end if;
end process;

done <= t_done;
player <= t_player;

process(t_col) is
variable temp : bit_vector(7 downto 0);
begin
	temp := x"01" ;
	move <= to_stdlogicvector(temp sll to_integer(unsigned(t_col)));
end process;

--Read address muxing
--This block provides the muxing logic to the picoblaze.  It uses the 
--port_id signal as the control signal
process(port_id, 
		  t_player, 
		  move_data_out,
		  mask_data_out,
		  black_board,
		  white_board,
		  t_col,
		  t_row,
		  t_play) is
	variable temp : std_logic_vector(7 downto 0);
begin
	--defaults
	case(port_id) is
		when x"00" => 
			in_port <= "0000000" & t_player;
		when x"01" =>
			in_port <= move_data_out;
		when x"02" =>
			in_port <= move_data_out;
		when x"03" =>
			in_port <= move_data_out;
		when x"04" =>
			in_port <= move_data_out;
		when x"05" =>
			in_port <= mask_data_out;
		when x"06" =>
			in_port <= mask_data_out;
		when x"07" =>
			in_port <= mask_data_out;
		when x"08" =>
			in_port <= mask_data_out;
		when x"09" =>
			in_port <= "00000" & t_row;
		when x"0a" =>
			temp := x"00";
			temp(to_integer(unsigned(t_col))) := '1';
			in_port <= temp;
		when x"0b" =>
			if(t_player ='0') then
				in_port <= black_board(to_integer(unsigned(t_row)));
			else 
				in_port <= white_board(to_integer(unsigned(t_row)));
			end if;
		when x"0c" =>
			if(t_player ='0') then
				in_port <= white_board(to_integer(unsigned(t_row)));
			else 
				in_port <= black_board(to_integer(unsigned(t_row)));
			end if;	
		when x"0e" =>
			in_port <= "0000000" & t_play;
		when x"0f" => --player 
			if(t_player = '0') then
				in_port <= gen_flip_vector(t_col, black_board);
			else
				in_port <= gen_flip_vector(t_col, white_board);
			end if;	
	   when x"12" => --op
			if(t_player = '0') then
				in_port <= gen_flip_vector(t_col, white_board);
			else
				in_port <= gen_flip_vector(t_col, black_board);
			end if;	
			
		when x"10" => --player
			if(t_player = '0') then
				in_port <= gen_a1_h8_vec(t_col,t_row, black_board);
			else
				in_port <= gen_a1_h8_vec(t_col,t_row, white_board);
			end if;	
		when x"13" => --op
			if(t_player = '0') then
				in_port <= gen_a1_h8_vec(t_col,t_row, white_board);
			else
				in_port <= gen_a1_h8_vec(t_col,t_row, black_board);
			end if;	
		when x"11" => --player
			if(t_player = '0') then
				in_port <= gen_a8_h1_vec(t_col,t_row, black_board);
			else
				in_port <= gen_a8_h1_vec(t_col,t_row, white_board);
			end if;	
		
		when x"14" => --op
			if(t_player = '0') then
				in_port <= gen_a8_h1_vec(t_col,t_row, white_board);
			else
				in_port <= gen_a8_h1_vec(t_col,t_row, black_board);
			end if;	
		when others =>
			in_port <= x"00";
	end case;
end process;

-- instantiations of mask and move generators
U_mask_gen : entity work.mask_gen PORT MAP(
		clk50 => clk50,
		reset => reset,
		w_bitboard => white_board,
		b_bitboard => black_board,
		player => t_player,
		sel => sel,
		row => t_row,
		col => t_col,
		data_out => mask_data_out);
		
U_move_gen : entity work.valid_move_gen PORT MAP(
		clk50 => clk50,
		reset => reset,
		w_bitboard => white_board,
		b_bitboard => black_board,
		player => t_player,
		sel => sel,
		num => num,
		data_out => move_data_out);

-- instantiation of picoblaze
--
-- address map:
-- 	player, 00
-- 	move_std, 01
-- 	move_flip, 02
-- 	move_a1_h8, 03
-- 	move_a8_h1, 04
-- 	mask_std, 05
-- 	mask_flip, 06
-- 	mask_a1_h8, 07
-- 	mask_a8_h1, 08
-- 	row, 09
-- 	col, 0a
-- 	player_board, 0b
-- 	op_board, 0c
-- 	invalid, 0d
-- 	play, 0e
--    player_board_flip, 0f
--    player_board_a1_h8, 10
--    player_board_a8_h1, 11
--    op_board_flip, 12
--    op_board_a1_h8, 13
--    op_board_a8_h1, 14

processor: kcpsm3
    port map(
		address       => address,
		instruction   => instruction,
		port_id       => port_id,
		write_strobe  => write_strobe,
		out_port      => out_port,
		read_strobe   => read_strobe,
		in_port       => in_port,
		interrupt     => '0',
		interrupt_ack => open,
		reset         => reset,
		clk           => clk50);
				

program: gl_ctrl
	port map(    
		address     => address,
		instruction => instruction,
		clk         => clk50);
	
end RTL;

